home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / lib / tclX-6.4 / tcl.tlib < prev    next >
Encoding:
Text File  |  1992-12-17  |  16.0 KB  |  662 lines

  1.  
  2. #@package: TclX-ArrayProcedures for_array_keys
  3.  
  4. proc for_array_keys {varName arrayName codeFragment} {
  5.     upvar $varName enumVar $arrayName enumArray
  6.  
  7.     if ![info exists enumArray] {
  8.     error "\"$arrayName\" isn't an array"
  9.     }
  10.  
  11.     set searchId [array startsearch enumArray]
  12.     while {[array anymore enumArray $searchId]} {
  13.     set enumVar [array nextelement enumArray $searchId]
  14.     uplevel $codeFragment
  15.     }
  16.     array donesearch enumArray $searchId
  17. }
  18.  
  19. #@package: TclX-assign_fields assign_fields
  20.  
  21. proc assign_fields {list args} {
  22.     foreach varName $args {
  23.         set value [lvarpop list]
  24.         uplevel "set $varName [list $value]"
  25.     }
  26. }
  27.  
  28. #@package: TclX-developer_utils saveprocs edprocs
  29.  
  30. proc saveprocs {fileName args} {
  31.     set fp [open $fileName w]
  32.     puts $fp "# tcl procs saved on [fmtclock [getclock]]\n"
  33.     puts $fp [eval "showprocs $args"]
  34.     close $fp
  35. }
  36.  
  37. proc edprocs {args} {
  38.     global env
  39.  
  40.     set tmpFilename /tmp/tcldev.[id process]
  41.  
  42.     set fp [open $tmpFilename w]
  43.     puts $fp "\n# TEMP EDIT BUFFER -- YOUR CHANGES ARE FOR THIS SESSION ONLY\n"
  44.     puts $fp [eval "showprocs $args"]
  45.     close $fp
  46.  
  47.     if [info exists env(EDITOR)] {
  48.         set editor $env(EDITOR)
  49.     } else {
  50.     set editor vi
  51.     }
  52.  
  53.     set startMtime [file mtime $tmpFilename]
  54.     system "$editor $tmpFilename"
  55.  
  56.     if {[file mtime $tmpFilename] != $startMtime} {
  57.     source $tmpFilename
  58.     echo "Procedures were reloaded."
  59.     } else {
  60.     echo "No changes were made."
  61.     }
  62.     unlink $tmpFilename
  63.     return
  64. }
  65.  
  66. #@package: TclX-forfile for_file
  67.  
  68. proc for_file {var filename code} {
  69.     upvar $var line
  70.     set fp [open $filename r]
  71.     while {[gets $fp line] >= 0} {
  72.         uplevel $code
  73.     }
  74.     close $fp
  75. }
  76.  
  77.  
  78. #@package: TclX-forrecur for_recursive_glob
  79.  
  80. proc for_recursive_glob {var globlist code {depth 1}} {
  81.     upvar $depth $var myVar
  82.     foreach globpat $globlist {
  83.         foreach file [glob -nocomplain $globpat] {
  84.             if [file isdirectory $file] {
  85.                 for_recursive_glob $var $file/* $code [expr {$depth + 1}]
  86.         }
  87.         set myVar $file
  88.         uplevel $depth $code
  89.         }
  90.     }
  91. }
  92.  
  93. #@package: TclX-globrecur recursive_glob
  94.  
  95. proc recursive_glob {globlist} {
  96.     set result ""
  97.     foreach pattern $globlist {
  98.         foreach file [glob -nocomplain $pattern] {
  99.             lappend result $file
  100.             if [file isdirectory $file] {
  101.                 set result [concat $result [recursive_glob $file/*]]
  102.             }
  103.         }
  104.     }
  105.     return $result
  106. }
  107.  
  108. #@package: TclX-help help helpcd helppwd apropos
  109.  
  110.  
  111. proc help:flattenPath {pathName} {
  112.     set newPath {}
  113.     foreach element [split $pathName /] {
  114.         if {"$element" == "."} {
  115.            continue
  116.         }
  117.         if {"$element" == ".."} {
  118.             if {[llength [join $newPath /]] == 0} {
  119.                 error "Help: name goes above subject directory root"}
  120.             lvarpop newPath [expr [llength $newPath]-1]
  121.             continue
  122.         }
  123.         lappend newPath $element
  124.     }
  125.     set newPath [join $newPath /]
  126.     
  127.  
  128.     if {("$newPath" == "") && [string match "/*" $pathName]} {
  129.         set newPath "/"}
  130.         
  131.     return $newPath
  132. }
  133.  
  134.  
  135. proc help:EvalPath {pathName} {
  136.     global TCLENV
  137.  
  138.     if {![string match "/*" $pathName]} {
  139.         if {"$pathName" == ""} {
  140.             return $TCLENV(help:curDir)}
  141.         if {"$TCLENV(help:curDir)" == "/"} {
  142.             set pathName "/$pathName"
  143.         } else {
  144.             set pathName "$TCLENV(help:curDir)/$pathName"
  145.         }
  146.     }
  147.     set pathName [help:flattenPath $pathName]
  148.     if {[string match "*/" $pathName] && ($pathName != "/")} {
  149.         set pathName [csubstr $pathName 0 [expr [length $pathName]-1]]}
  150.  
  151.     return $pathName    
  152. }
  153.  
  154.  
  155. proc help:Display {line} {
  156.     global TCLENV
  157.     if {$TCLENV(help:lineCnt) >= 23} {
  158.         set TCLENV(help:lineCnt) 0
  159.         puts stdout ":" nonewline
  160.         flush stdout
  161.         gets stdin response
  162.         if {![lempty $response]} {
  163.             return 0}
  164.     }
  165.     puts stdout $line
  166.     incr TCLENV(help:lineCnt)
  167. }
  168.  
  169.  
  170. proc help:DisplayFile {filepath} {
  171.  
  172.     set inFH [open $filepath r]
  173.     while {[gets $inFH fileBuf] >= 0} {
  174.         if {![help:Display $fileBuf]} {
  175.             break}
  176.     }
  177.     close $inFH
  178.  
  179. }    
  180.  
  181.  
  182. proc help:ListDir {dirPath} {
  183.     set dirList {}
  184.     set fileList {}
  185.     if {[catch {set dirFiles [glob $dirPath/*]}] != 0} {
  186.         error "No files in subject directory: $dirPath"}
  187.     foreach fileName $dirFiles {
  188.         if [file isdirectory $fileName] {
  189.             lappend dirList "[file tail $fileName]/"
  190.         } else {
  191.             lappend fileList [file tail $fileName]
  192.         }
  193.     }
  194.    return [list [lsort $dirList] [lsort $fileList]]
  195. }
  196.  
  197.  
  198. proc help:DisplayColumns {nameList} {
  199.     set count 0
  200.     set outLine ""
  201.     foreach name $nameList {
  202.         if {$count == 0} {
  203.             append outLine "   "}
  204.         append outLine $name
  205.         if {[incr count] < 4} {
  206.             set padLen [expr 17-[clength $name]]
  207.             if {$padLen < 3} {
  208.                set padLen 3}
  209.             append outLine [replicate " " $padLen]
  210.         } else {
  211.            if {![help:Display $outLine]} {
  212.                return}
  213.            set outLine ""
  214.            set count 0
  215.         }
  216.     }
  217.     if {$count != 0} {
  218.         help:Display $outLine}
  219.     return
  220. }
  221.  
  222.  
  223.  
  224. proc help {{subject {}}} {
  225.     global TCLENV
  226.  
  227.     set TCLENV(help:lineCnt) 0
  228.  
  229.  
  230.     if {($subject == "help") || ($subject == "?")} {
  231.         help:DisplayFile "$TCLENV(help:root)/help"
  232.         return
  233.     }
  234.  
  235.     set request [help:EvalPath $subject]
  236.     set requestPath "$TCLENV(help:root)$request"
  237.  
  238.     if {![file exists $requestPath]} {
  239.         error "Help:\"$request\" does not exist"}
  240.     
  241.     if [file isdirectory $requestPath] {
  242.         set dirList [help:ListDir $requestPath]
  243.         set subList  [lindex $dirList 0]
  244.         set fileList [lindex $dirList 1]
  245.         if {[llength $subList] != 0} {
  246.             help:Display "\nSubjects available in $request:"
  247.             help:DisplayColumns $subList
  248.         }
  249.         if {[llength $fileList] != 0} {
  250.             help:Display "\nHelp files available in $request:"
  251.             help:DisplayColumns $fileList
  252.         }
  253.     } else {
  254.         help:DisplayFile $requestPath
  255.     }
  256.     return
  257. }
  258.  
  259.  
  260.  
  261. proc helpcd {{dir /}} {
  262.     global TCLENV
  263.  
  264.     set request [help:EvalPath $dir]
  265.     set requestPath "$TCLENV(help:root)$request"
  266.  
  267.     if {![file exists $requestPath]} {
  268.         error "Helpcd: \"$request\" does not exist"}
  269.     
  270.     if {![file isdirectory $requestPath]} {
  271.         error "Helpcd: \"$request\" is not a directory"}
  272.  
  273.     set TCLENV(help:curDir) $request
  274.     return    
  275. }
  276.  
  277.  
  278. proc helppwd {} {
  279.         global TCLENV
  280.         echo "Current help subject directory: $TCLENV(help:curDir)"
  281. }
  282.  
  283.  
  284. proc apropos {name} {
  285.     global TCLENV
  286.  
  287.     set TCLENV(help:lineCnt) 0
  288.  
  289.     set aproposCT [scancontext create]
  290.     scanmatch -nocase $aproposCT $name {
  291.         set path [lindex $matchInfo(line) 0]
  292.         set desc [lrange $matchInfo(line) 1 end]
  293.         if {![help:Display [format "%s - %s" $path $desc]]} {
  294.             return}
  295.     }
  296.     foreach brief [glob -nocomplain $TCLENV(help:root)/*.brf] {
  297.         set briefFH [open $brief]
  298.         scanfile $aproposCT $briefFH
  299.         close $briefFH
  300.     }
  301.     scancontext delete $aproposCT
  302. }
  303.  
  304. global TCLENV TCLPATH
  305.  
  306. set TCLENV(help:root) [searchpath $TCLPATH help]
  307. set TCLENV(help:curDir) "/"
  308. set TCLENV(help:outBuf) {}
  309.  
  310. #@package: TclX-packages packages autoprocs
  311.  
  312. proc packages {{option {}}} {
  313.     global TCLENV
  314.     set packList {}
  315.     foreach key [array names TCLENV] {
  316.         if {[string match "PKG:*" $key]} {
  317.             lappend packList [string range $key 4 end]
  318.         }
  319.     }
  320.     if [lempty $option] {
  321.         return $packList
  322.     } else {
  323.         if {$option != "-location"} {
  324.             error "Unknow option \"$option\", expected \"-location\""
  325.         }
  326.         set locList {}
  327.         foreach pack $packList {
  328.             set fileId [lindex $TCLENV(PKG:$pack) 0]
  329.             
  330.             lappend locList [list $pack [concat $TCLENV($fileId) \
  331.                                              [lrange $TCLENV(PKG:$pack) 1 2]]]
  332.         }
  333.         return $locList
  334.     }
  335. }
  336.  
  337. proc autoprocs {} {
  338.     global TCLENV
  339.     set procList {}
  340.     foreach key [array names TCLENV] {
  341.         if {[string match "PROC:*" $key]} {
  342.             lappend procList [string range $key 5 end]
  343.         }
  344.     }
  345.     return $procList
  346. }
  347.  
  348. #@package: TclX-directory_stack pushd popd dirs
  349.  
  350. global TCLENV(dirPushList)
  351.  
  352. set TCLENV(dirPushList) ""
  353.  
  354. proc pushd {args} {
  355.     global TCLENV
  356.  
  357.     if {[llength $args] > 1} {
  358.         error "bad # args: pushd [dir_to_cd_to]"
  359.     }
  360.     set TCLENV(dirPushList) [linsert $TCLENV(dirPushList) 0 [pwd]]
  361.  
  362.     if {[llength $args] != 0} {
  363.         cd [glob $args]
  364.     }
  365. }
  366.  
  367. proc popd {} {
  368.     global TCLENV
  369.  
  370.     if [llength $TCLENV(dirPushList)] {
  371.         cd [lvarpop TCLENV(dirPushList)]
  372.         pwd
  373.     } else {
  374.         error "directory stack empty"
  375.     }
  376. }
  377.  
  378. proc dirs {} { 
  379.     global TCLENV
  380.     echo [pwd] $TCLENV(dirPushList)
  381. }
  382.  
  383. #@package: TclX-set_functions union intersect intersect3 lrmdups
  384.  
  385. proc union {lista listb} {
  386.     set full_list [lsort [concat $lista $listb]]
  387.     set check_element [lindex $full_list 0]
  388.     set outlist $check_element
  389.     foreach element [lrange $full_list 1 end] {
  390.     if {$check_element == $element} continue
  391.     lappend outlist $element
  392.     set check_element $element
  393.     }
  394.     return $outlist
  395. }
  396.  
  397. proc lrmdups {list} {
  398.     set list [lsort $list]
  399.     set result [lvarpop list]
  400.     lappend last $result
  401.     foreach element $list {
  402.     if {$last != $element} {
  403.         lappend result $element
  404.         set last $element
  405.     }
  406.     }
  407.     return $result
  408. }
  409.  
  410.  
  411. proc intersect3 {list1 list2} {
  412.     set list1Result ""
  413.     set list2Result ""
  414.     set intersectList ""
  415.  
  416.     set list1 [lrmdups $list1]
  417.     set list2 [lrmdups $list2]
  418.  
  419.     while {1} {
  420.         if [lempty $list1] {
  421.             if ![lempty $list2] {
  422.                 set list2Result [concat $list2Result $list2]
  423.             }
  424.             break
  425.         }
  426.         if [lempty $list2] {
  427.         set list1Result [concat $list1Result $list1]
  428.             break
  429.         }
  430.         set compareResult [string compare [lindex $list1 0] [lindex $list2 0]]
  431.  
  432.         if {$compareResult < 0} {
  433.             lappend list1Result [lvarpop list1]
  434.             continue
  435.         }
  436.         if {$compareResult > 0} {
  437.             lappend list2Result [lvarpop list2]
  438.             continue
  439.         }
  440.         lappend intersectList [lvarpop list1]
  441.         lvarpop list2
  442.     }
  443.     return [list $list1Result $intersectList $list2Result]
  444. }
  445.  
  446. proc intersect {list1 list2} {
  447.     set intersectList ""
  448.  
  449.     set list1 [lsort $list1]
  450.     set list2 [lsort $list2]
  451.  
  452.     while {1} {
  453.         if {[lempty $list1] || [lempty $list2]} break
  454.  
  455.         set compareResult [string compare [lindex $list1 0] [lindex $list2 0]]
  456.  
  457.         if {$compareResult < 0} {
  458.             lvarpop list1
  459.             continue
  460.         }
  461.  
  462.         if {$compareResult > 0} {
  463.             lvarpop list2
  464.             continue
  465.         }
  466.  
  467.         lappend intersectList [lvarpop list1]
  468.         lvarpop list2
  469.     }
  470.     return $intersectList
  471. }
  472.  
  473.  
  474.  
  475. #@package: TclX-show_procedures showproc showprocs
  476.  
  477. proc showproc {procname} {
  478.     if [lempty [info procs $procname]] {demand_load $procname}
  479.     set arglist [info args $procname]
  480.     set nargs {}
  481.     while {[llength $arglist] > 0} {
  482.         set varg [lvarpop arglist 0]
  483.         if [info default $procname $varg defarg] {
  484.         lappend nargs [list $varg $defarg]
  485.         } else {
  486.         lappend nargs $varg
  487.         }
  488.     }
  489.     format "proc %s \{%s\} \{%s\}\n" $procname $nargs [info body $procname]
  490. }
  491.  
  492. proc showprocs {args} {
  493.     if [lempty $args] { set args [info procs] }
  494.     set out ""
  495.  
  496.     foreach i $args {
  497.     foreach j $i { append out [showproc $j] "\n"}
  498.     }
  499.     return $out
  500. }
  501.  
  502.  
  503. #@package: TclX-stringfile_functions read_file write_file
  504.  
  505. proc read_file {fileName {numBytes {}}} {
  506.     set fp [open $fileName]
  507.     if {$numBytes != ""} {
  508.         set result [read $fp $numBytes]
  509.     } else {
  510.         set result [read $fp]
  511.     }
  512.     close $fp
  513.     return $result
  514.  
  515. proc write_file {fileName args} {
  516.     set fp [open $fileName w]
  517.     foreach string $args {
  518.         puts $fp $string
  519.     }
  520.     close $fp
  521. }
  522.  
  523.  
  524. #@package: TclX-Compatibility execvp
  525.  
  526. proc execvp {progname args} {
  527.     execl $progname $args
  528. }
  529.  
  530. #@package: TclX-convertlib convert_lib
  531.  
  532. proc convert_lib {tclIndex packageLib {ignore {}}} {
  533.     if {[file tail $tclIndex] != "tclIndex"} {
  534.         error "Tail file name numt be `tclIndex': $tclIndex"}
  535.     set srcDir [file dirname $tclIndex]
  536.  
  537.     if {[file extension $packageLib] != ".tlib"} {
  538.         append packageLib ".tlib"}
  539.  
  540.  
  541.     set tclIndexFH [open $tclIndex r]
  542.     while {[gets $tclIndexFH line] >= 0} {
  543.         if {([cindex $line 0] == "#") || ([llength $line] != 2)} {
  544.             continue}
  545.         if {[lsearch $ignore [lindex $line 1]] >= 0} {
  546.             continue}
  547.         lappend entryTable([lindex $line 1]) [lindex $line 0]
  548.     }
  549.     close $tclIndexFH
  550.  
  551.     set libFH [open $packageLib w]
  552.     foreach srcFile [array names entryTable] {
  553.         set srcFH [open $srcDir/$srcFile r]
  554.         puts $libFH "#@package: $srcFile $entryTable($srcFile)\n"
  555.         copyfile $srcFH $libFH
  556.         close $srcFH
  557.     }
  558.     close $libFH
  559.     buildpackageindex $packageLib
  560. }
  561.  
  562. #@package: TclX-profrep profrep
  563.  
  564. proc profrep:summarize {profDataVar stackDepth sumProfDataVar} {
  565.     upvar $profDataVar profData $sumProfDataVar sumProfData
  566.  
  567.     if {(![info exists profData]) || ([catch {array size profData}] != 0)} {
  568.         error "`profDataVar' must be the name of an array returned by the `profile off' command"
  569.     }
  570.     set maxNameLen 0
  571.     foreach procStack [array names profData] {
  572.         if {[llength $procStack] < $stackDepth} {
  573.             set sigProcStack $procStack
  574.         } else {
  575.             set sigProcStack [lrange $procStack 0 [expr {$stackDepth - 1}]]
  576.         }
  577.         set maxNameLen [max $maxNameLen [clength $sigProcStack]]
  578.         if [info exists sumProfData($sigProcStack)] {
  579.             set cur $sumProfData($sigProcStack)
  580.             set add $profData($procStack)
  581.             set     new [expr [lindex $cur 0]+[lindex $add 0]]
  582.             lappend new [expr [lindex $cur 1]+[lindex $add 1]]
  583.             lappend new [expr [lindex $cur 2]+[lindex $add 2]]
  584.             set $sumProfData($sigProcStack) $new
  585.         } else {
  586.             set sumProfData($sigProcStack) $profData($procStack)
  587.         }
  588.     }
  589.     return $maxNameLen
  590. }
  591.  
  592. proc profrep:sort {sumProfDataVar sortKey} {
  593.     upvar $sumProfDataVar sumProfData
  594.  
  595.     case $sortKey {
  596.         {calls} {set keyIndex 0}
  597.         {real}  {set keyIndex 1}
  598.         {cpu}   {set keyIndex 2}
  599.         default {
  600.             error "Expected a sort of: `calls',  `cpu' or ` real'"}
  601.     }
  602.  
  603.  
  604.     foreach procStack [array names sumProfData] {
  605.         set key [format "%016d" [lindex $sumProfData($procStack) $keyIndex]]
  606.         lappend keyProcList [list $key $procStack]
  607.     }
  608.     set keyProcList [lsort $keyProcList]
  609.  
  610.  
  611.     for {set idx [expr [llength $keyProcList]-1]} {$idx >= 0} {incr idx -1} {
  612.         lappend sortedProcList [lindex [lindex $keyProcList $idx] 1]
  613.     }
  614.     return $sortedProcList
  615. }
  616.  
  617.  
  618. proc profrep:print {sumProfDataVar sortedProcList maxNameLen outFile
  619.                     userTitle} {
  620.     upvar $sumProfDataVar sumProfData
  621.     
  622.     if {$outFile == ""} {
  623.         set outFH stdout
  624.     } else {
  625.         set outFH [open $outFile w]
  626.     }
  627.  
  628.  
  629.     set stackTitle "Procedure Call Stack"
  630.     set maxNameLen [max $maxNameLen [clength $stackTitle]]
  631.     set hdr [format "%-${maxNameLen}s %10s %10s %10s" $stackTitle \
  632.                     "Calls" "Real Time" "CPU Time"]
  633.     if {$userTitle != ""} {
  634.         puts $outFH [replicate - [clength $hdr]]
  635.         puts $outFH $userTitle
  636.     }
  637.     puts $outFH [replicate - [clength $hdr]]
  638.     puts $outFH $hdr
  639.     puts $outFH [replicate - [clength $hdr]]
  640.  
  641.  
  642.     foreach procStack $sortedProcList {
  643.         set data $sumProfData($procStack)
  644.         puts $outFH [format "%-${maxNameLen}s %10d %10d %10d" $procStack \
  645.                             [lindex $data 0] [lindex $data 1] [lindex $data 2]]
  646.     }
  647.     if {$outFile != ""} {
  648.         close $outFH
  649.     }
  650. }
  651.  
  652.  
  653. proc profrep {profDataVar sortKey stackDepth {outFile {}} {userTitle {}}} {
  654.     upvar $profDataVar profData
  655.  
  656.     set maxNameLen [profrep:summarize profData $stackDepth sumProfData]
  657.     set sortedProcList [profrep:sort sumProfData $sortKey]
  658.     profrep:print sumProfData $sortedProcList $maxNameLen $outFile $userTitle
  659.  
  660. }
  661.